package com.bingxue.edu.tools;

import cn.hutool.core.convert.Convert;
import com.bingxue.edu.common.enums.ChangeTypeEnum;
import com.bingxue.edu.common.enums.OperateSourceEnum;
import com.bingxue.edu.common.enums.OperateStatusEnum;
import com.bingxue.edu.common.enums.OrderStatusEnum;
import com.bingxue.edu.common.enums.PayTypeEnum;
import com.bingxue.edu.common.enums.StudentClassEnum;
import com.bingxue.edu.management.education.model.entity.ClassInfo;
import com.bingxue.edu.management.education.model.entity.EnrollChangeRecord;
import com.bingxue.edu.management.education.model.entity.Enrollment;
import com.bingxue.edu.management.education.model.entity.LessonStudent;
import com.bingxue.edu.management.education.model.req.ClassCancelVerifyReq;
import com.bingxue.edu.management.education.service.ClassCancelService;
import com.bingxue.edu.management.education.service.ClassInfoService;
import com.bingxue.edu.management.education.service.EnrollChangeRecordService;
import com.bingxue.edu.management.education.service.EnrollmentService;
import com.bingxue.edu.management.education.service.LessonStudentService;
import com.bingxue.edu.management.shop.model.entity.Order;
import com.bingxue.edu.management.shop.model.entity.OrderItem;
import com.bingxue.edu.management.shop.model.entity.Refund;
import com.bingxue.edu.management.shop.service.OrderItemService;
import com.bingxue.edu.management.shop.service.OrderService;
import com.bingxue.edu.management.shop.service.RefundService;
import com.bingxue.edu.framework.common.util.ValidationUtils;
import com.mybatisflex.core.logicdelete.LogicDeleteManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.bingxue.edu.common.util.EduUtil.generateRefundId;
import static com.bingxue.edu.management.education.model.entity.table.EnrollChangeRecordTableDef.ENROLL_CHANGE_RECORD;
import static com.bingxue.edu.management.education.model.entity.table.LessonStudentTableDef.LESSON_STUDENT;
import static com.bingxue.edu.management.shop.model.entity.table.OrderTableDef.ORDER;
import static com.mybatisflex.core.query.QueryMethods.count;

/**
 * 处理重复缴费导致的订单状态异常
 * @author panbo
 * @since 2024/11/23
 */
@SpringBootTest
public class OrderStatusFixedTool {

    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private LessonStudentService lessonStudentService;
    @Autowired
    private EnrollmentService enrollmentService;
    @Autowired
    private EnrollChangeRecordService enrollChangeRecordService;
    @Autowired
    private RefundService refundService;
    @Autowired
    private ClassInfoService classInfoService;
    @Autowired
    private ClassCancelService classCancelService;

//    @Test
//    @Transactional(rollbackFor = Exception.class)
    public void fixed() {
        // 订单1，系统中正常，富友已手动退费。
        String orderId1 = "20241107144339658521";
        // 订单2 系统中已取消，富友已支付
        String orderId2 = "20241107144340930352";
        String outTradeNo4orderId2 = "500496528326";
        boolean needCancelClass = false;

        System.out.printf("开始处理订单, orderId1: %s, orderId2: %s%n", orderId1, orderId2);
        Order order1 = orderService.getById(orderId1);
        ValidationUtils.throwIfNull(order1, "订单1为空");
        ValidationUtils.throwIfNotEqual(order1.getStatus(), OrderStatusEnum.PAID, "订单1状态不对");
        Order order2 = orderService.getById(orderId2);
        ValidationUtils.throwIfNull(order2, "订单2为空");
        ValidationUtils.throwIfNotEqual(order2.getStatus(), OrderStatusEnum.CANCELED, "订单2状态不对");
        ValidationUtils.throwIfNotEqual(order1.getActualTotalPrice(), order2.getActualTotalPrice(), "订单价格不对");

        List<OrderItem> orderItemList1 = orderItemService.getListByOrderId(orderId1);
        ValidationUtils.throwIf(orderItemList1.isEmpty(), "订单项1为空");
        List<OrderItem> orderItemList2 = orderItemService.getListByOrderId(orderId2);
        ValidationUtils.throwIf(orderItemList2.isEmpty(), "订单项2为空");
        ValidationUtils.throwIf(orderItemList1.size() != orderItemList2.size(), "订单项不相同");
        for (int i = 0; i < orderItemList1.size(); i++) {
            OrderItem orderItem1 = orderItemList1.get(i);
            OrderItem orderItem2 = orderItemList2.get(i);
            ValidationUtils.throwIfNotEqual(orderItem1.getClassId(), orderItem2.getClassId(), "订单项班级不相同");
        }
        for (int i = 0; i < orderItemList1.size(); i++) {
            OrderItem orderItem1 = orderItemList1.get(i);
            OrderItem orderItem2 = orderItemList2.get(i);
            Enrollment enrollment = enrollmentService.getStudentEnrollment(orderItem1.getClassId(), orderItem1.getStudentId());
            ValidationUtils.throwIfNull(enrollment, "报名id未找到");

            // 修改lesson student的order_item_id，改为order_item2，因为order_item2未退款。
            boolean update1 = lessonStudentService.updateChain()
                    .set(LESSON_STUDENT.ORDER_ITEM_ID, orderItem2.getId())
                    .where(LESSON_STUDENT.ENROLLMENT_ID.eq(enrollment.getId()))
                    .and(LESSON_STUDENT.STUDENT_CLASS_STATUS.eq(StudentClassEnum.NORMAL))
                    .and(LESSON_STUDENT.ORDER_ITEM_ID.eq(orderItem1.getId()))
                    .update();
            ValidationUtils.throwIf(!update1, "update1未完成");
            // 修改报名变更记录的business id为order_item2
            boolean update2 = enrollChangeRecordService.updateChain()
                    .set(ENROLL_CHANGE_RECORD.BUSINESS_ID, orderItem2.getId())
                    .where(ENROLL_CHANGE_RECORD.ENROLLMENT_ID.eq(enrollment.getId()))
                    .and(ENROLL_CHANGE_RECORD.CHANGE_TYPE.eq(ChangeTypeEnum.NEW_ENROLL))
                    .and(ENROLL_CHANGE_RECORD.OPERATE_STATUS.eq(OperateStatusEnum.SUCCESS))
//                    .and(ENROLL_CHANGE_RECORD.BUSINESS_ID.eq(orderItem1.getId()))
                    .update();
            ValidationUtils.throwIf(!update2, "update2未完成");

            // 处理重复报名的情况。
            List<Integer> countList = lessonStudentService.queryChain()
                    .select(count())
                    .where(LESSON_STUDENT.ENROLLMENT_ID.eq(enrollment.getId()))
                    .and(LESSON_STUDENT.STUDENT_CLASS_STATUS.eq(StudentClassEnum.NORMAL))
                    .groupBy(LESSON_STUDENT.LESSON_ID)
                    .listAs(Integer.class);
            List<Integer> filterList = countList.stream().filter(item -> item > 1).toList();
            if(!filterList.isEmpty()) {
                System.out.printf("报名id: %s, 存在重复报名%n", enrollment.getId());
            }
            if(needCancelClass) {
                // 处理lesson student
                // 将正确状态的lessonstudent数据设置deleted（根据order_item_id查询）
                lessonStudentService.updateChain()
                        .where(LESSON_STUDENT.ENROLLMENT_ID.eq(enrollment.getId()))
                        .and(LESSON_STUDENT.STUDENT_CLASS_STATUS.eq(StudentClassEnum.NORMAL))
                        .and(LESSON_STUDENT.ORDER_ITEM_ID.ne(orderItem2.getId()))
                        .remove();

                // TODO 处理数据
                boolean exist = enrollChangeRecordService.existPendingCancelRecord(enrollment.getId());
                ValidationUtils.throwIf(exist,"存在未完成的退课单,不能重复申请");

                countList = lessonStudentService.queryChain()
                        .select(count())
                        .where(LESSON_STUDENT.ENROLLMENT_ID.eq(enrollment.getId()))
                        .and(LESSON_STUDENT.STUDENT_CLASS_STATUS.eq(StudentClassEnum.NORMAL))
                        .groupBy(LESSON_STUDENT.LESSON_ID)
                        .listAs(Integer.class);

                filterList = countList.stream().filter(item -> item > 1).toList();
                ValidationUtils.throwIfNotEmpty(filterList,"存在重复课次，请处理");

                List<LessonStudent> lessonStudentList = lessonStudentService.queryChain()
                        .where(LESSON_STUDENT.ENROLLMENT_ID.eq(enrollment.getId()))
                        .and(LESSON_STUDENT.STUDENT_CLASS_STATUS.eq(StudentClassEnum.NORMAL))
                        .list();

                // 创建退课
                Set<String> orderItemIdSet = lessonStudentList.stream().map(LessonStudent::getOrderItemId).collect(Collectors.toSet());
                ValidationUtils.throwIf(orderItemIdSet.size() > 1, "不支持跨订单退费");
                // 创建退款单
                Refund refund = initNewRefund(orderItem2, enrollment.getId(), lessonStudentList);
                refundService.save(refund);
                // 创建变更记录
                ClassInfo classInfo = classInfoService.getById(enrollment.getClassId());
                EnrollChangeRecord enrollChangeRecord = initCancelRecord(enrollment, classInfo, refund.getCancelLessonIndexes());
                enrollChangeRecord.setBusinessId(refund.getId());
                // 保存报名信息变更记录，状态为审核中
                enrollChangeRecordService.save(enrollChangeRecord);
                // 审核退课
                ClassCancelVerifyReq classCancelVerifyReq = new ClassCancelVerifyReq();
                classCancelVerifyReq.setRecordId(enrollChangeRecord.getId());
                classCancelVerifyReq.setRefundType(PayTypeEnum.FUIOU);
                classCancelVerifyReq.setFinAccountId(PayTypeEnum.FUIOU.getValue());
                classCancelService.passClassCancel(classCancelVerifyReq);
                // 恢复deleted
                LogicDeleteManager.execWithoutLogicDelete(() -> {
                    lessonStudentService.updateChain()
                            .where(LESSON_STUDENT.ENROLLMENT_ID.eq(enrollment.getId()))
                            .and(LESSON_STUDENT.STUDENT_CLASS_STATUS.eq(StudentClassEnum.NORMAL))
                            .and(LESSON_STUDENT.ORDER_ITEM_ID.ne(orderItem2.getId()))
                            .and(LESSON_STUDENT.DELETED.eq(true))
                            .set(LESSON_STUDENT.DELETED, false)
                            .update();
                });
            }
        }

        // 订单1状态设置为已取消
        boolean update1 = orderService.updateChain().where(ORDER.ID.eq(order1.getId()))
                .set(ORDER.STATUS, OrderStatusEnum.CANCELED)
                .set(ORDER.PAY_OFF, false)
                .set(ORDER.CANCEL_TIME, order2.getCancelTime())
                .update();
        ValidationUtils.throwIf(!update1, "update1失败");
        // 订单2设置为已支付
        boolean update2 = orderService.updateChain().where(ORDER.ID.eq(order2.getId()))
                .set(ORDER.STATUS, OrderStatusEnum.PAID)
                .set(ORDER.PAY_OFF, true)
                .set(ORDER.FIN_ACCOUNT_ID, order1.getFinAccountId())
                .set(ORDER.PAY_TIME, order1.getPayTime())
                .set(ORDER.OUT_TRADE_NO, outTradeNo4orderId2)
                .set(ORDER.CANCEL_TIME, null)
                .update();
        ValidationUtils.throwIf(!update2, "update2失败");
        System.out.printf("结束处理订单, orderId1: %s, orderId2: %s%n", orderId1, orderId2);
    }

    private Refund initNewRefund(OrderItem orderItem, String enrollmentId, List<LessonStudent> cancelLessonStudentList) {
        // 计算退款金额
        BigDecimal refundPrice = cancelLessonStudentList.stream().map(LessonStudent::getLessonPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 退课顺序列表
        List<Integer> cancelLessonIndexes = cancelLessonStudentList.stream().map(LessonStudent::getLessonIndex).sorted().toList();

        Refund refund = new Refund();
        refund.setId(generateRefundId());
        refund.setOrderId(orderItem.getOrderId());
        refund.setOrderItemId(orderItem.getId());
        refund.setEnrollmentId(enrollmentId);
        refund.setStudentId(orderItem.getStudentId());
        refund.setClassId(orderItem.getClassId());
        refund.setCancelLessonIndexes(cancelLessonIndexes);
        refund.setRefundPrice(refundPrice);
        refund.setRefundOff(false);
        refund.setChangeType(ChangeTypeEnum.CANCEL_LESSON);
        refund.setOperateSource(OperateSourceEnum.BACKEND);

        return refund;
    }

    private EnrollChangeRecord initCancelRecord(Enrollment enrollment, ClassInfo classInfo, List<Integer> lessonIndexList) {
        String lessonIndexListStr = Convert.toStr(lessonIndexList);
        EnrollChangeRecord enrollChangeRecord = new EnrollChangeRecord();
        enrollChangeRecord.setEnrollmentId(enrollment.getId());
        enrollChangeRecord.setStudentId(enrollment.getStudentId());
        enrollChangeRecord.setChangeType(ChangeTypeEnum.CANCEL_LESSON);
        enrollChangeRecord.setOriginalClassId(classInfo.getId());
        enrollChangeRecord.setOriginalLessonIndexes(lessonIndexList);
        enrollChangeRecord.setOperateStatus(OperateStatusEnum.VERIFYING);
        String details = "从[%s]%s，课次为第%s次课，共%d次课".formatted(classInfo.getName(), ChangeTypeEnum.CANCEL_LESSON.getLabel(), lessonIndexListStr, lessonIndexList.size());
        enrollChangeRecord.setDetails(details);
        enrollChangeRecord.setOperateSource(OperateSourceEnum.BACKEND);
        return enrollChangeRecord;
    }
}
